package server;
import common.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Timer;
import java.lang.Math;

/** Classe che si occupa di gestire tutti i metodi chiamati durante la Partita.
 *
 */
public class Partita {

	private Server ms;
	private Gioco gioco;
	
	private ArrayList<Utente> utente = new ArrayList<Utente>();
	private ArrayList<Utente> utenteDaInserire = new ArrayList<Utente>();
	private ArrayList<Utente> utenteDaRimuovere = new ArrayList<Utente>();
	
	private int utenteCorrente=0;
	private int tokenUtCorrente=-2;
	
	private final int MAX_UTENTI = 8;
	private final int ETA_MAX = 120;
	
	private ArrayList<Dinosauro> dinoMossi = new ArrayList<Dinosauro>();
	private ArrayList<Dinosauro> dinoUsati = new ArrayList<Dinosauro>();
	private ArrayList<Dinosauro> dinoMorti = new ArrayList<Dinosauro>(); 
	
	private Timer t30s = new Timer();
	private Timer t2m = new Timer();

	private Mappa mappa;
	
	/** 
	 * Costruttore dell'oggetto partita: avvia il partita vera e propria si occupa dell'accesso/uscita partita, delle azioni dei giocatori e del cambio del turno.
	 * @param ms E' un oggetto di classe Server utile alla comunicazione da server a client durante la partita (es. cambio del turno) 
	 * @param gioc E' un oggetto di classe Gioco serve all'interazione tra la parte del server dedicata al login (classe Gioco) e alla partita (classe Partita)
	 */
	public Partita(Server ms, Gioco gioc){
		mappa = new Mappa();
		this.ms = ms;
		this.gioco = gioc;
		utente = new ArrayList<Utente>();
	}
	
	/**
	 * Metodo che restituisce la lista di giocatori.
	 * @param token Token dell'utente che fa la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>String[]</b> giocatori</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>; 
	 */
	public ArrayList<Object> listaGiocatori(int token){
		ArrayList<Object> result = new ArrayList<Object>();
		Utente ut = gioco.controlloToken(token);
		if(ut==null){
			result.add(false);
			result.add(3);
			return result;
		}
		if(utente.size()==0){
			result.add(false);
			result.add(95);
			return result;
		}else{
			String[] username = new String[utente.size()];
			for(int i=0; i<utente.size(); i++){
				username[i]=utente.get(i).getUserID();
			}
			result.add(true);
			result.add(username);
			return result;
		}
	}
	
	/**
	 * Metodo che consente l'accesso a partita se non viene superato il limite d'utenti.
	 * @param token Token dell'utente che fa la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>Boolean</b> cambioTurnoDaFare</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public synchronized ArrayList<Object> accessoPartita(int token){
		ArrayList<Object> result = new ArrayList<Object>();
		Utente newUtente = gioco.controlloToken(token);
		Boolean cambioTurno = false;
		if(newUtente==null){
			result.add(false);
			result.add(3);
			return result;
		}else if((utente.size() + utenteDaInserire.size() - utenteDaRimuovere.size()) == MAX_UTENTI){
			result.add(false);
			result.add(4);
			return result;
		}else if(newUtente.getSpecie()==null){
			//l'utente non ha una razza
			result.add(false);
			result.add(96);
			return result;
		}else{
			if(utenteDaInserire.indexOf(newUtente)==-1){
				//controllo che non sia già nella lista degli utenti da inserire
				utenteDaInserire.add(newUtente);
			}
			if(utente.size()==0 && utenteDaInserire.size()==1){
				utenteCorrente=0;
				cambioTurno = true;
			}else{
				cambioTurno = false;
			}
			result.add(true);
			result.add(cambioTurno);
			return result;
		}
	}
	
	/**
	 * Metodo che consente l'uscita dalla partita.
	 * @param token Token dell'utente che fa la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public synchronized ArrayList<Object> uscitaPartita(int token){
		ArrayList<Object> result = new ArrayList<Object>();
		Utente remUtente = gioco.controlloToken(token);
		if(remUtente==null){
			result.add(false);
			result.add(3);
			return result;
		}

		if(utenteDaRimuovere.indexOf(remUtente)==-1 && (utente.indexOf(remUtente)!=-1 || utenteDaInserire.indexOf(remUtente) != -1)){
			utenteDaRimuovere.add(remUtente);
		}
		
		if(remUtente.getToken()==tokenUtCorrente){
			cambioTurno();
			t2m.cancel();
		}
		result.add(true);
		return result;
	}
	
	/**
	 * Metodo che consente all'utente di accettare il suo turno.
	 * @param token Token dell'utente che fa la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public ArrayList<Object> confermaTurno(int token){
		ArrayList<Object> result = new ArrayList<Object>();
		if(token==tokenUtCorrente){
			//stop timer 30 sec
			t30s.cancel();
	
			//start timer 2 min 
			t2m = setTimerPassaTurno(120, token);
			
			result.add(true);
			return result;
		}else{
			result.add(false);
			result.add(3);
			return result;
		}
	}

	/**
	 * Metodo che si preoccupa di aggiornare la lista degli utenti connessi alla partita:<br />
	 * aggiunge gli utenti che hanno richiesto l'entrata in partita (dinosauri compresi)<br />
	 * rimuove gli utenti che hanno richiesto l'uscita dalla partita (dinosuauri compresi)<br />
	 * cambia l'utente corrente mettendo eventualmente in pausa la partita<br />
	 */
	public void cambioTurno(){
		
		int numUtRim=0;
		int numUtIns=0;
		String username;
		
		//rimuovo i dinosauri morti dalla lista degli utenti che aspettano il loro turno
		while(!dinoMorti.isEmpty()){
			rimuoviDinoDaUtente(dinoMorti.get(0));
		}
		
		//mando messaggi di specie morta
		
		for(int i=0; i<utenteDaRimuovere.size(); i++){
			Utente ut = utenteDaRimuovere.get(i); 
			if(ut.getSpecie()==null && ut.getToken()!=tokenUtCorrente){
				try {
					ms.specieMorta(ut.getUserID(), false);
//					System.out.println("Partita: specieMorta da cambio turno");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
//		System.out.println("Partita: Inizio - Ci sono "+utente.size()+" utenti.");
//		System.out.println("Partita: Inizio - Ci sono "+utenteDaRimuovere.size()+" utenti da rimuovere.");
//		System.out.println("Partita: Inizio - Ci sono "+utenteDaInserire.size()+" utenti da inserire.");
		//controlla che ci siano utentiDaRimuovere
		while(!utenteDaRimuovere.isEmpty()){
			Utente utRem = utenteDaRimuovere.get(0);
			int idRem = utente.indexOf(utRem);
			if(utRem.getSpecie()!=null){
				//se la specie non e' gia' estinta tolgo i dinosauri dalla mappa
				ArrayList<Dinosauro> dinosauro = utRem.getSpecie().getArrayDino();
				for(int j=0; j<dinosauro.size(); j++){
					Dinosauro dinoToRem = dinosauro.get(j);
					mappa.getCasella(dinoToRem.getPosX(), dinoToRem.getPosY()).removeDinosauro();
					mappa.getCasella(dinoToRem.getPosX(), dinoToRem.getPosY()).setOccupata(false);
				}
			}
			
			if(utente.indexOf(utRem) < utenteCorrente){
				utenteCorrente--;
			}
			utenteDaRimuovere.remove(0);
			if(utente.indexOf(utRem)!=-1){
				utente.remove(idRem);
			}else{
				utenteDaInserire.remove(utRem);
			}
			numUtRim++;
		}
		
		//controlla che ci siano utentiDaInserire
		Utente newUtente;
		while(!utenteDaInserire.isEmpty()){
			newUtente = utenteDaInserire.get(0);
			ArrayList<Dinosauro> dinosauro = newUtente.getSpecie().getArrayDino();
			int x, y;		
			//controlla che i dinosauri siano in posizioni non occupate
			for(int i=0; i<dinosauro.size(); i++){
				x = dinosauro.get(i).getPosX();
				y = dinosauro.get(i).getPosY();
				
				if(mappa.occupata(x, y)){
					Casella casLibera = mappa.getCasellaLibera();
					casLibera.setOccupata(true);
					dinosauro.get(i).setPosX(casLibera.getX());
					dinosauro.get(i).setPosY(casLibera.getY());

					casLibera.insertDinosauro(dinosauro.get(i));
				}else{
					mappa.getCasella(x, y).insertDinosauro(dinosauro.get(i));
					mappa.getCasella(x, y).setOccupata(true);
				}
			}
			utente.add(newUtente);
			utenteDaInserire.remove(0);
			numUtIns++;
		}

		if(utente.size()==0){
//			System.out.println("Partita: Fine -  Non ci sono giocatori e metto in pausa la partita");
			this.utenteCorrente = 0;
			this.tokenUtCorrente = -2;
		}else{
			//svuoto l'arrayList di dinoMossi
			dinoMossi = new ArrayList<Dinosauro>();
			dinoUsati = new ArrayList<Dinosauro>();
			
			int idUtenteProssimo = this.utenteCorrente + 1;
			if(idUtenteProssimo >= utente.size() || tokenUtCorrente == -2){
				idUtenteProssimo = 0;
			}
		
//			System.out.println("Partita: Utente prossimo: "+idUtenteProssimo);
			this.utenteCorrente = idUtenteProssimo;
			this.tokenUtCorrente = utente.get(utenteCorrente).getToken();
			
			username = utente.get(utenteCorrente).getUserID();
		
			try {
				//invio il cambio turno a tutti i client e setto il timer di 30 sec
				ms.cambioTurno(username);
				t30s = setTimerPassaTurno(30, this.tokenUtCorrente);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
//		System.out.println("Partita: Fine - Ci sono "+utente.size()+" utenti.");
//		System.out.println("Partita: Fine - Ci sono "+utenteDaRimuovere.size()+" utenti da rimuovere.");
//		System.out.println("Partita: Fine - Ci sono "+utenteDaInserire.size()+" utenti da inserire.");
		
		gioco.salvaUtenti();
		gioco.salvaNomeSpeci();
		mappa.salvaMappa();
		
	}
	
	/**
	 * Metodo che consente ad un utente di passare il suo turno (i suoi dati -punteggio, vita- vengono aggiornati)
	 * @param token Token dell'utente che fa la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public synchronized ArrayList<Object> passaTurno(int token){
		t2m.cancel();
		ArrayList<Object> result = new ArrayList<Object>();
		Utente ut = gioco.controlloToken(token);
		if(ut!=null){
			if(ut.getToken()==tokenUtCorrente){
				//calcolo il punteggio
				ArrayList<Dinosauro> dinoVivi = ut.getSpecie().getArrayDino();
				int punti=0;
				for(int i=0; i<dinoVivi.size(); i++){
					punti = punti + 1 + dinoVivi.get(i).getDimensione();
				}
				ut.setPunteggio(punti);
				ut.getSpecie().incrementaEta();
				mappa.evolvi();
				if(ut.getSpecie().getEta()==ETA_MAX){
					//controllo estinzione
					ut.estinzione();
					try {
						ms.specieMorta(ut.getUserID(), true);
					} catch (IOException e) {
						e.printStackTrace();
					}
					result.add(false);
					result.add(101);
					return result;
				}else{
					//rimuovo i dinosauri morti
					for(int i=0; i<dinoVivi.size(); i++){
						if(dinoVivi.get(i).getVita() >= dinoVivi.get(i).getVitaMax()){
							
							Dinosauro dino = dinoVivi.get(i);
							rimuoviDinoDaMappa(dino);
							int numDino = rimuoviDinoDaUtente(dino);
							
							if(numDino == 0){
								try {
									ms.specieMorta(ut.getUserID(), true);
								} catch (IOException e) {
									e.printStackTrace();
								}
								result.add(false);
								result.add(101);	//se morto per inedia e la razza e' estinta 
								return result;
							}else{
								result.add(false);
								result.add(9);	//se morto per inedia e la razza e' estinta 
								return result;
							}
						}
					}
					
				}
				
				result.add(true);
				return result;
			}else{
				//non e' il tuo turno
				result.add(false);
				result.add(10);
				return result;
			}
		}else{
			//token sbagliato
			result.add(false);
			result.add(3);
			return result;
		}
	}
	
	/**
	 * Metodo che restituisce la mappa generale.
	 * @param token Token dell'utente che fa la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>int</b> altezza</code>; 
	 * <code><b>int</b> larghezza</code>; <code><b>String[][]</b> mappaLocale</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public ArrayList<Object> mappaGenerale(int token){
		ArrayList<Object> result = new ArrayList<Object>();
		Utente ut = gioco.controlloToken(token);
		if(ut==null){
			result.add(false);
			result.add(3);
			return result;
		}else if(utente.indexOf(ut) == -1 || ut.getSpecie()== null){
			result.add(false);
			result.add(5);
			return result;
		}else{
			String[][] mappaGenerale = ut.getVistaMappa();
			
			result.add(true);
			result.add(mappaGenerale.length);
			result.add(mappaGenerale[0].length);
			result.add(mappaGenerale);
			return result;
		}
	}
	
	/**
	 * Metodo che resituisce la vista locale.<br />
	 * @param token Token dell'utente che fa la richiesta
	 * @param idDino Id del dinosauro di cui viene fatta la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>int</b> xCellaAltoSx</code>; 
	 * <code><b>int</b> yCellaAltoSx</code>; <code><b>int</b> altezza</code>; <code><b>int</b> larghezza</code>; 
	 * <code><b>String[][]</b> mappaLocale</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public ArrayList<Object> vistaLocale(int token, String idDino){
		ArrayList<Object> result = new ArrayList<Object>();
		if(gioco.controlloToken(token)!=null){
			Utente ut = gioco.controlloToken(token);
			if(ut==null){
				result.add(false);
				result.add(0);
				return result;
			}
			Dinosauro dino = ut.getSpecie().getDinosauro(idDino);
			if(dino==null){
				result.add(false);
				result.add(6);
				return result;
			}
			
			int vista=0;
			
			int xStart;
			int yStart;
			
			if(dino.getDimensione()==1){
				vista = 2;
			}else if(dino.getDimensione()==2 || dino.getDimensione()==3){
				vista = 3;
			}else if(dino.getDimensione()==4 || dino.getDimensione()==5){
				vista = 4;
			}
			
			xStart=dino.getPosX()-vista;
			yStart=dino.getPosY()-vista;
			
			if(xStart<0){
				xStart=0;
			}
			if(yStart<0){
				yStart=0;
			}
			
			
			
			String mappaLocFog[][] = mappa.getMappaLocale(dino.getPosX(), dino.getPosY(), vista, true);
			String mappaLoc[][] = mappa.getMappaLocale(dino.getPosX(), dino.getPosY(), vista, false);
			
			//aggiorno la mappa dell'utente
			ut.setVistaMappa(mappaLocFog ,xStart , yStart, mappaLoc.length , mappaLoc[0].length );
			//ritorno la mappa
			
			result.add(true);
			result.add(xStart);
			result.add(yStart);
			result.add(mappaLoc.length);
			result.add(mappaLoc[0].length);
			result.add(mappaLoc);
			return result;
		}else{
			result.add(false);
			result.add(0);
			return result;
		}
	}
	
	/**
	 * Metodo che restituisce lo stato di un dinosauro.
	 * @param token Token dell'utente che fa la richiesta
	 * @param idDino Id del dinosauro di cui viene fatta la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>String</b> username</code>; <code><b>String</b> nomeSpecie</code>;
	 * <code><b>char</b> tipoDinosauro</code>; <code><b>int</b> posizioneX</code>; <code><b>int</b> posizioneY</code>; <code><b>int</b> dimensione</code>; 
	 * {<code><b>int</b> energia</code>; <code><b>int</b> vita</code>}<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>
	 */
	public ArrayList<Object> statoDinosauro(int token, String idDino){
		ArrayList<Object> result = new ArrayList<Object>();
		String utDino = usernameFromDino(idDino);
		Utente ut = gioco.controlloToken(token);
		Utente utConDino = getUtenteFromId(utDino);
		Dinosauro dino = utConDino.getSpecie().getDinosauro(idDino);
		if(dino==null){
			result.add(false);
			result.add(6);
			return result;
		}
		if(ut != null && this.utente.indexOf(ut)!=-1){
			result.add(true);
			result.add(utConDino.getUserID());
			result.add(utConDino.getSpecie().getNomeSpecie());
			result.add(dino.getTipo());
			result.add(dino.getPosX());
			result.add(dino.getPosY());
			result.add(dino.getDimensione());
			if(ut.getUserID().compareTo(utDino)==0){
				result.add(dino.getEnergia());
				result.add(dino.getVita());
			}
			return result;
		}else{
			result.add(false);
			result.add(3);
			return result;
		}
	}
	
	/**
	 * Metodo che consente restituisce la lista di dinosauri.
	 * @param token Token dell'utente che fa la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>String[]</b> idDinosauri</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>; 
	 */
	public ArrayList<Object> listaDinosauri(int token){
		ArrayList<Object> result = new ArrayList<Object>();
		Utente ut = gioco.controlloToken(token);
		if(ut==null){
			result.add(false);
			result.add(3);
			return result;
		}else if(utente.indexOf(ut) == -1){
			result.add(false);
			result.add(5);
			return result;
		}else{
			ArrayList<Dinosauro> listaDino = new ArrayList<Dinosauro>();
			listaDino = ut.getSpecie().getArrayDino();
			String[] idDino = new String[listaDino.size()];
			result.add(true);
			for(int i=0; i<listaDino.size(); i++){
				idDino[i]=listaDino.get(i).getIdDino();
			}
			result.add(idDino);
			result.add(listaDino.size());
			return result;
		}
	}
	
	/**
	 * Metodo che esegue l'azione cresci di un singolo dinosauro.
	 * @param token Token dell'utente che fa la richiesta
	 * @param idDino Id del dinosauro di cui viene fatta la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>String[]</b> idDinosauri</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public ArrayList<Object> cresciDinosauro(int token, String idDino){
		ArrayList<Object> result = new ArrayList<Object>();
		Utente ut = gioco.controlloToken(token);
		if(ut!=null){
			if(ut.getToken()==tokenUtCorrente){
				Dinosauro dino = ut.getSpecie().getDinosauro(idDino);
				if(dino==null){
					result.add(false);
					result.add(6);
					return result;
				}
				if(dinoUsati.indexOf(dino)==-1){	
					int energia = dino.getEnergia();
					int costo = 1000*dino.getDimensione()/2;
					if(energia - costo < 0){
						
						rimuoviDinoDaMappa(dino);
						int numDino = rimuoviDinoDaUtente(dino);
						
						if(numDino > 0){
							result.add(false);
							result.add(9);	//se morto per inedia e la razza non e' estinta 
							return result;	
						}else{
							try {
								ms.specieMorta(ut.getUserID(), true);
							} catch (IOException e) {
								e.printStackTrace();
							}
							result.add(false);
							result.add(101);	//se morto per inedia e la razza e' estinta 
							return result;
						}
						
					}else{
						if(dino.getDimensione()<5){
							dino.setEnergia( - costo);
							dino.evolvi();
							dinoMossi.add(dino);
							dinoUsati.add(dino);
							result.add(true);
							result.add("ok");
							return result;
						}else{
							//raggiunta la dimensione massima
							result.add(false);
							result.add(8);
							return result;
						}
					}
				}else{
					//dino gia' mosso
					result.add(false);
					result.add(8);
					return result;
				}
			}else{
			//non e' il tuo turno
				result.add(false);
				result.add(10);
				return result;
			}
		}else{
			result.add(false);
			result.add(3);
			return result;
		}
	}
	
	/**
	 * Metodo che esegue l'azione muovi di un singolo dinosauro.
	 * @param token Token dell'utente che fa la richiesta
	 * @param idDino Id del dinosauro di cui viene fatta la richiesta
	 * @param xEnd Posizione X di destinazione
	 * @param yEnd Posizione Y di destinazione
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>Boolean</b> fattoCombattimento</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public ArrayList<Object> muoviDinosauro(int token, String idDino, int xEnd, int yEnd){
		ArrayList<Object> result = new ArrayList<Object>();
		
		Utente ut = gioco.controlloToken(token);
		if(ut != null){
			if(ut.getToken()==tokenUtCorrente){
				Dinosauro dino = ut.getSpecie().getDinosauro(idDino);
				if(dino==null){
					result.add(false);
					result.add(6);
					return result;
				}
				int distanza = mappa.checkMovimento(dino.getPosX(), dino.getPosY(), xEnd, yEnd);
					if(distanza!=-1 && dinoMossi.indexOf(dino)==-1 && dinoUsati.indexOf(dino)==-1){
						Casella destinazione = mappa.getCasella(xEnd, yEnd);
						//controllo se c'è un dinosauro
						Dinosauro dinoAvversario = destinazione.getDinosauro();
						if(dinoAvversario == null){
							//non c'e' un dinosauro avversario: se posso mangio
							dinoMossi.add(dino);
							int energiaDino = spostamentoSemplice(dino, destinazione, distanza);
							if(energiaDino <= 0){
								//dinosauro morto
								rimuoviDinoDaMappa(dino);
								int numDino = rimuoviDinoDaUtente(dino);
								
								if(numDino > 0){
									result.add(false);
									result.add(9);	//se morto per inedia e la razza non e' estinta 
									return result;	
								}else{
									try {
										ms.specieMorta(ut.getUserID(), true);
									} catch (IOException e) {
										e.printStackTrace();
									}
									result.add(false);
									result.add(101);	//se morto per inedia e la razza e' estinta 
									return result;
								}
							}
							mangia(dino, destinazione);
							result.add(true);
							result.add(false);
							return result;
						
						}else if(dinoAvversario.getTipo()=='c' || dino.getTipo()=='c'){
							//c'e' un dinosauro carnivoro e quindi combatto
							
							dinoMossi.add(dino);
							int resFight;
							resFight=combatti(dino, dinoAvversario, distanza);
							if(resFight != 3){
								result.add(true);
								result.add(true);
								result.add(resFight);
								return result;
							}else{
								try {
									ms.specieMorta(ut.getUserID(), true);
								} catch (IOException e) {
									e.printStackTrace();
								}
								result.add(false);
								result.add(101);
								return result;
							}
							
						}else{
							//movimento non concesso: incontro tra due erbivori
							result.add(false);
							result.add(8);
							return result;
						}
					}else{
						result.add(false);
						result.add(8);
						return result;//movimento non concesso
					}
			}else{
				//errore non e' il tuo turno;
				result.add(false);
				result.add(10);
				return result;
			}
		}else{
			//errore token.
			result.add(false);
			result.add(3);
			return result;
		}
	}
	
	
	/**
	 * Metodo che esegue l'azione deponi uovo di un singolo dinosauro.
	 * @param token Token dell'utente che fa la richiesta
	 * @param idDino Id del dinosauro di cui viene fatta la richiesta
	 * @return ArrayList di Oggetti: <code><b>Boolean</b> true</code>; <code><b>String</b> idDinosauroCreato</code>;<br />
	 * ArrayList di Oggetti - errore: <code><b>Boolean</b> false</code>; <code><b>int</b> numeroErrore </code>;
	 */
	public ArrayList<Object> deponiUovo(int token, String idDino){
		ArrayList<Object> result = new ArrayList<Object>();
		Utente ut = gioco.controlloToken(token);
		
		if(ut!=null){
			if(utente.indexOf(ut)!=-1){
				if(ut.getToken()==tokenUtCorrente){
					String username = usernameFromDino(idDino);
					Dinosauro dinoMamma =  ut.getSpecie().getDinosauro(idDino);
						
						if(ut.getUserID().compareTo(username)==0){
							if(dinoUsati.indexOf(dinoMamma)==-1){
								int costoEnergia = 1500;
								if(dinoMamma.getEnergia() >= costoEnergia){
									int xUovo=0;
									int yUovo=0;
									int i=0, j=0;
									for(i=0; i < 8 && mappa.occupata(xUovo, yUovo); i++){
										xUovo=dinoMamma.getPosX() - 1+(int)Math.round(Math.random()*2);
										yUovo=dinoMamma.getPosY() - 1+(int)Math.round(Math.random()*2);
										if (xUovo<0 || yUovo<0 ||xUovo>=Mappa.SIZE_X || yUovo>=Mappa.SIZE_Y){
											xUovo=0;
											yUovo=0;
										}
									}
									
									if(i==8){
										for(j=0; j<8 && mappa.occupata(xUovo, yUovo); j++){
											switch(j){
												case 0:
													xUovo = dinoMamma.getPosX() - 1;
													yUovo = dinoMamma.getPosY() - 1;
													break;
												case 1:
													xUovo = dinoMamma.getPosX() - 1;
													yUovo = dinoMamma.getPosY();
													break;
												case 2:
													xUovo = dinoMamma.getPosX() - 1;
													yUovo = dinoMamma.getPosY() + 1;
													break;
												case 3:
													xUovo = dinoMamma.getPosX();
													yUovo = dinoMamma.getPosY() + 1;
													break;
												case 4:
													xUovo = dinoMamma.getPosX() + 1;
													yUovo = dinoMamma.getPosY() + 1;
													break;
												case 5:
													xUovo = dinoMamma.getPosX() + 1;
													yUovo = dinoMamma.getPosY();
													break;
												case 6:
													xUovo = dinoMamma.getPosX() + 1;
													yUovo = dinoMamma.getPosY() - 1;
													break;
												case 7:
													xUovo = dinoMamma.getPosX();
													yUovo = dinoMamma.getPosY() - 1;
													break;
											}
											
											if (xUovo<0 || yUovo<0 ||xUovo>Mappa.SIZE_X || yUovo>Mappa.SIZE_Y){
												xUovo=0;
												yUovo=0;
											}
											
										}
									}
									
									if(i==8 && j==8){
										//tutte le caselle sono occupate
										result.add(false);
										result.add(8);
										return result;
									}
					
									Dinosauro uovo = ut.getSpecie().inserisciUovo(xUovo, yUovo);
									dinoMamma.setEnergia(- costoEnergia);
									
									dinoMossi.add(uovo);
									dinoUsati.add(uovo);
									dinoMossi.add(dinoMamma);
									dinoUsati.add(dinoMamma);
									
									mappa.getCasella(xUovo, yUovo).setOccupata(true);
									mappa.getCasella(xUovo, yUovo).insertDinosauro(uovo);
									
									result.add(true);
									result.add(uovo.getIdDino());
									return result;
							}else{
								rimuoviDinoDaMappa(dinoMamma);
								int numDino = rimuoviDinoDaUtente(dinoMamma);
								
								if(numDino > 0){
									result.add(false);
									result.add(9);	//se morto per inedia e la razza non e' estinta 
									return result;	
								}else{
									try {
										ms.specieMorta(ut.getUserID(), true);
									} catch (IOException e) {
										e.printStackTrace();
									}
									result.add(false);
									result.add(101);	//se morto per inedia e la razza non e' estinta 
									return result;
								}
							}
						}else{
							//dinosauro gia' mosso
							result.add(false);
							result.add(8);
							return result;
						}
						
					}else{
						//il dinosauro non e' tuo
						result.add(false);
						result.add(9);
						return result;
					}
				}else{
					//non e' il tuo turno
					result.add(false);
					result.add(10);
					return result;
				}
			}else{
				//non in partita
				result.add(false);
				result.add(5);
				return result;	
			}
		}else{
			//token non valido
			result.add(false);
			result.add(3);
			return result;
		}
	}
	
	/**
	 * Metodo che esegue l'azione mangia sugli oggetti Dinosauro e Casella.
	 * @param dino Dinosauro che esegue l'azione
	 * @param dest Casella su cui viene eseguita l'azione
	 * @return <code><b>int</b> energiaDinosauro</code>
	 */
	private int mangia(Dinosauro dino, Casella dest){
		if(dino.getTipo()=='c' && dest.getTipo().compareTo("C")==0){
			Carogna car = (Carogna)dest;
			dino.setEnergia(car.getEnergia());
			mappa.spostaCarogna(dest.getX(), dest.getY());
			return dino.getEnergia();
		}else if(dino.getTipo()=='e' && dest.getTipo().compareTo("V")==0){
			Vegetazione veg = (Vegetazione)dest;
			dino.setEnergia(veg.getEnergia());
			veg.setEnergia(0);
			//mappa.spostaVegetazione(dest.getX(), dest.getY());
			return dino.getEnergia();
		}else{
			return -1;
		}
	}
	
	/**
	 * Metodo che esegue lo spostamento senza controlli.
	 * @param dino Dinosauro che esegue l'azione
	 * @param dest Cella di destinazione
	 * @return <code><b>int</b> energiaDinosauro</code>
	 */
	private int spostamentoSemplice(Dinosauro dino, Casella dest, int distanza){
		Casella casOld = mappa.getCasella(dino.getPosX(), dino.getPosY());
		casOld.insertDinosauro(null);
		casOld.setOccupata(false);
		dest.insertDinosauro(dino);
		dest.setOccupata(true);
		
		dino.setPosX(dest.getX());
		dino.setPosY(dest.getY());
		if(distanza!=0){
			dino.setEnergia(- (int)(10*Math.pow(2, distanza)));
		}
		return dino.getEnergia();
	}
	
	/**
	 * Il metodo fa il combattimento tra i due dinosauri. Se vince il dinosauro attaccante, questo viene spostato
	 * nella coordinate del dinosauro che si difende. Altrimenti il dinosauro attaccante viene rimosso.
	 * @param dinoA Dinosauro che attacca
	 * @param dinoD Dinosauro che si difende
	 * @return <code><b>int</b> risultatoCombattimento</code> (1: vince A, 2: vince B, 3: vince B e A razza estinta)
	 */
	private int combatti(Dinosauro dinoA, Dinosauro dinoB, int distanza){
		
		int energiaDino = spostamentoSemplice(dinoA, mappa.getCasella(dinoB.getPosX(), dinoB.getPosY()), distanza);
		
		if(dinoA.getForza() >= dinoB.getForza() && energiaDino > 0){
			if(dinoA.getTipo()=='c'){
				dinoA.setEnergia((int)(dinoB.getEnergia()*0.75));
			}
			
			rimuoviDinoDaMappa(dinoB);
			return 1;
		}else{
			spostamentoSemplice(dinoB, mappa.getCasella(dinoB.getPosX(), dinoB.getPosY()), 0);
			if(dinoB.getTipo()=='c'){
				dinoB.setEnergia((int)(dinoA.getEnergia()*0.75));
			}
			
			rimuoviDinoDaMappa(dinoA);
			int numDino = rimuoviDinoDaUtente(dinoA);
			
			if(numDino > 0){
				return 2;
			}else{
				return 3;
			}
		}
	}
	
	/**
	 * Metodo che setta un Timer per passare il turno dopo un tot di secondi prefissati.
	 * @param secondi Numero di secondi dopo i quali scatta il metodo passaTurno()
	 * @param token Token dell'utente per cui e' deve essere settato il passaTurno()
	 * @return <code><b>Timer</b> timerDelMetodo</code>
	 */
	private Timer setTimerPassaTurno(double secondi, int token){
		Timer timer = new Timer();
		TimerPT task = new TimerPT(this, token);
		timer.schedule(task, (int)(1000 * secondi));
		return timer;
	}
	
	/**
	 * Metodo che rimuove il dinosauro dalla mappa
	 * @param dino Dinosauro da rimuovere
	 */
	private void rimuoviDinoDaMappa(Dinosauro dino){
		dinoMorti.add(dino);
		String idDino = dino.getIdDino();
		Casella cas = mappa.getCasella(dino.getPosX(), dino.getPosY());
		if(cas.getDinosauro().getIdDino().compareTo(idDino)==0){
			cas.setOccupata(false);
			cas.insertDinosauro(null);
		}
	}
	/**
	 * Metodo che rimuove il dinosauro dalla lista dell'utente e controlla se la razza e' estinta
	 * @param dino Dinosauro da rimuovere
	 * @return <code><b>int</b> numeroDinosauri</code>
	 */
	private int rimuoviDinoDaUtente(Dinosauro dino){
		
		int indexDinoMorto = dinoMorti.indexOf(dino);
		dinoMorti.remove(indexDinoMorto);
		
		String idDino = dino.getIdDino();
		Utente ut = getUtenteFromId(usernameFromDino(idDino));
		ut.getSpecie().uccidiDinosauro(idDino);
		int numDino = ut.getSpecie().getArrayDino().size();
		//controllo che non sia l'ultimo dinosauro
		if(numDino==0){
			ut.estinzione();
			utenteDaRimuovere.add(ut);
		}
		
		return numDino;
	}
	
	/**
	 * Metodo che ritorna Username dell'utente cui appartiene il dinosauro
	 * @param idDino
	 * @return <code><b>String</b> username</code>
	 */
	private String usernameFromDino(String idDino){
		int iFind = idDino.indexOf(":");
		return idDino = idDino.substring(0,iFind);
	}
	
	/**
	 * Metodo che ritorna Utente dal suo Username
	 * @param username
	 * @return <code><b>Utente</b> utente</code>
	 */
	private Utente getUtenteFromId(String username){
		int i=0;
		while(i<utente.size() && utente.get(i).getUserID().compareTo(username)!=0){
			i++;
		}
		if(i<utente.size()){
			return utente.get(i);
		}else{
			return null;
		}
	}
	
	public Mappa getMappa(){
		return mappa;
	}
}